%%\chapter{Introduction}
%%
%%Modern embedded systems are composed of multicore SOCs that require
%%careful thought about concurrency. C is the
%%most commonly used language to program such low level systems because
%%it is simple and expressive, but it is
%%a double-edged blade. Low level code written in C can more easily and
%%directly interface with hardware, but it can also be plagued with
%%difficult bugs, especially concurrency-related bugs and memory bugs like
%%use after free.
%%
%%Concurrent, high-level user space programs that do not directly interface with
%%hardware, on the other hand, are usually written in a
%%high-level language, such as Rust or Go, which abstracts concurrency
%%and provides memory safety. Rust, Go, and other High Level Languages (HLL's)
%%will usually ensure that there is never an out of bounds error, use
%%after free error, or unsafe cast. HLL's can also provide native concurrency
%%support through primitives like channels. The downsides of HLLs is that those
%%nice featues come at a cost of garbage collection and many runtime checks.
%%Despite the shortcomings, HLLs are still preferred to C programs because fast,
%%modern computers negate the performance cost. Now that embedded devices are also very fast,
%%the possibility of using a HLL on a performant embedded system is undeniable.
%%
%%Embedded programmers are often drawn towards using Linux for their work
%%because then they can write their embedded program in user space with a
%%high level language in order to avoid the difficulty and poor concurrency
%%support of C. Popular platforms that use this paradigm include
%%the Raspi and Beaglebone. However, embedded programs that run in user space suffer
%%from significant event latency because external interrupts
%%must shuffle their way through the kernel. Additionally, the kernel's scheduler
%%will also constantly preempt the program. This performance loss is compounded by the
%%performance penalties that HLL's also impose on programs.
%%Usually, an experienced programmer does not even want or need the
%%kernel, but they pay the price just to run the high-level embedded code.
%%
%%Traditional operating systems impose expensive and redundant checks on
%%high-level programs. For example,
%%Go already ensures that different threads cannot access each other's memory and that null pointers
%%will not be dereferenced. The OS is intended to work with buggy C programs though, so it must still switch
%%page tables when switching processes and be prepared for page faults when bad accesses occur. This machinery
%%is expensive and redundant for programs written in a HLL. Since embedded applications only run a single
%%program, it is possible to completely do away with the OS underneath a high-level program and regain the
%%lost performance without any degredation in safety.
%%
%%There are ongoing efforts to bring high-level languages to desktop
%%operating system kernels and also single-core microcontrollers, but
%%there is no known system which provides a high-level language environment for
%%multicore SOCs. Singularity <cite> and Biscuit <cite> are desktop
%%operating system kernels, written in Sing\# and Go, which focus on
%%hosting user-space programs. Copper <cite> and MicroPython <cite>
%%are small embedded toolkits, written in Rust and Python, which aim
%%to provide a high-level programming environment for single-core
%%microcontrollers. Multicore SOCs have, so far, been left out of the
%%picture. This thesis presents a new embedded toolkit, the Golang Embedded
%%RunTime (GERT), which is specifically intended for concurrent, bare-metal embedded applications.

%%GERT is a modified version of the Go runtime that can run faster on bare hardware without an OS.
%%One of the reasons that programs written in a HLL are slower than the equivalent C
%%program is because of the redundant isolation mechanisms that the OS provides. For example,
%%Go already ensures that different threads cannot access each other's memory and that null pointers
%%will not be dereferenced. The OS is intended to work with buggy C programs though, so it must still switch
%%page tables when switching processes and be prepared for page faults when bad accesses occur. This machinery
%%is expensive and redundant for programs written in a HLL.
%%
%%Because of this,
%%it should be OK to run Go threads in the same address space and the OS should not have to maintain
%%different page tables for each process in a Go program.
%%
%%Even though programs written in a HLL are slower than the equivalent C program in userspace,
%%
%%HLLs already provide isolation as a language feature so the 

%%GERT is a bare-metal, Go-based embedded toolkit for multicore ARMv7a processors.
%%It was developed in order to make bare-metal programming
%%easier for ARMv7a SOCs with the help of Go's channels, goroutines, and isolation.
%%G.E.R.T can run on a single-core processor but its effectiveness is substantially
%%reduced because any blocking operation can lock the whole system. On the other hand,
%%G.E.R.T will automatically scale to utilize all available cpus in multicore systems
%%because the Go runtime automatically scales to all available cpus. GERT is not intended
%%to outperform bare-metal C, but rather to provide isolation and native concurrency
%%support in a bare-metal environment.
%%
%%One particular concern about using a garbage-collected language, such as Go,
%%for low-level code is GC pause times. In Linux, a GC pause prevents the program from
%%responding to any input and producing any output; the program is literally paused.
%%GERT gets around this issue by allowing interrupt handlers to execute even when the
%%world is stopped due to a garbage collection. The only caveat is that interrupt handlers
%%cannot contain blocking operations because then execution could funnel into the Go scheduler
%%and lead to a catastrophe.

\chapter{Why Write System Code in Go?}

At first glance, Go code looks a lot like C. There are no
classes and the language has a strong type system.
This already makes Go a good systems language, but Go's
greatest feature is its built-in support for concurrency through
goroutines and channels. Goroutines are lightweight threads that
the Go runtime can schedule without help from the operating system.
Channels are typed FIFO queues which can help to serialize
asynchronous events, perhaps coming from several goroutines.
With these features and familiarity, writing programs in Go comes naturally to a C
programmer, but with the added bonus that a Go program is also
memory safe because of runtime checks and a garbage collection system.
%%With these features, Go feels like an updated version
%%of C for multicore systems, but without buffer overflows and
%%null pointer dereferences.


\section{Go Runtime Organization}
Go's implementation is reminiscent of a small OS. There are three basic
abstractions in the runtime: G's, M's, and P's. A G, or goroutine, is an
executable fragment of Go code, like a function or group of functions. In a concurrent program,
each fragment of Go code will get its
own G. M's are just OS threads; they can be executing Go code, blocked in a system call,
or idle. Finally, a P represents a processor, or the resources necessary to
allow execution. M's cannot execute code unless they are associated with a P.
It is the Go scheduler's job to associate G's, M's, and P's with each other so
that code can run. Go's threads are lightweight and
cooperatively scheduled\footnote{Go code is not totally cooperative because goroutines can be pre-empted during a function call. Users can write critical sections to avoid this though}
so that execution only transfers during
blocking operations. The runtime also manages its own pool of memory
and exports its own atomic primitives through the standard "sync"
package. In fact, Go provides most of the common OS primitives natively
in its standard libraries \cite{gostd}.

Go relies on the OS for priveleged operations. Since it runs in userspace,
the Go runtime cannot interface with physical hardware so it uses the OS
to get the time, allocate memory, receive signals.


\section{Go Memory Safety}
Like most high-level languages, Go does not allow the programmer to unsafely
manipulate memory. This means that there is no way to unsafely cast from one data type
to another, it is impossible to use a pointer after it is freed, and accessing
an array out of bounds yields a runtime error. Go also does not allow pointer arithmetic.
These properties are provided by bounds checking all array accesses, a strong type system,
and the lack of a $free()$ function.

Instead of letting the programmer free memory, Go
has a garbage collector which automatically frees memory with no incoming pointers.
The garbage collector is a costly abstraction though because it must scan through all
the pointers in the program. In the worst case scenario, the program must be
stopped while the GC runs, but recent improvements to Go have enabled concurrent garbage collection \cite{gogc}.
GC pauses are still noticeable though.

Compared to C, the properties of Go might seem like training wheels, but this is exactly
the point. The majority of bugs in a C program can be traced to an out of bounds access
(buffer overruns), use-after-free, or null pointer dereference \cite{cbugs}. These issues are so commonplace in userspace
programs, that OS kernels
attempt to preempt the problem by inserting guard pages all over the user program's
address space. In a bare-metal embedded system, though, there is no kernel which can help
mitigate the effects of a memory safety bug. The outcome of triggering a memory safty bug in an
embedded system is usually program curruption and total failure. Preventing such a scenario
is one of the goals of GERT.


\begin{figure} [h]
\begin{center}
  \begin{tabular}{ | l | l | l | l | l | l |}
    \hline
    Platform & Index OOB & User-after-free & Null Dereference & Correctness & Race Conditions \\ \hline
    Bare Metal C & \Checkmark & \Checkmark & \Checkmark & \Checkmark & \Checkmark\\ \hline
    GERT & panic & \XSolidBrush & panic & \Checkmark & detectable\\ \hline
  \end{tabular}
\end{center}
  \caption{Bugs That GERT Programs Can Have}  \label{fig:comparison}
\end{figure}

Compared to a bare-metal C program, a GERT program is memory safe. The table in
\ref{fig:comparison} summarizes the bugs that GERT programs will not experience.
Instead of crashing from a memory safety bug, a GERT program will panic. In Go, panics
can be recovered so execution can be resumed. GERT does not categorically prevent any
other bugs from occuring, such as correctness bugs or race conditions but Go does have
a race detector which can help identify race conditions.

\section{Tolerating the Garbage Collector}
Go uses a garbage collector to clean up dangling pointers and prevent
use-after-free errors, but it can have serious performance implications
for an embedded system. First of all, the garbage collector may allow
an excessive amount of unused memory to build up before running a scan.
This can cause SOCs with small amounts of RAM to run out of memory. GERT
does not attempt to alleviate this problem in any way because the operating
assumption is that powerful multicore SOCs will also have at least 1GB of RAM.
A quick scan through DigiKey does confirm this assumption. The other problem
with the garbage collector is that it has to "stop the world" sometimes in order
to perform its function. This process involves pausing the program and scanning
all of its pointers.

GERT mitigates the effects of a GC collection in two ways, one intentional
and one unintentional. In an embedded system, the danger of a
GC collection lies in missing external events. The way GERT intentionally mitigates
the effects of the garbage collector is by allowing interrupts to be serviced
even while the world is stopped. This is possible as long as the interrupt
handler does not execute a blocking operation. The other way GERT unintentionally
coexists with the garbage collector is because many embedded programs are
inherently static. Static embedded programs have a known memory use at compile time so
there is no need to allocate memory at run time and count its references. In fact, some embedded
platform libraries do not even have \textit{malloc} so all memory use must be static.
%%It relies on the OS
%%to provide time, memory, and signals.

%%Embedded systems are increasingly relying on dedicated peripherals to
%%provide service, instead of very fast cpus. SOCs contain dedicated
%%silicon peripherals to help with everything from serial communication to
%%interrupt priority filtering. These peripherals free the cpus from bit-banging
%%high-frequency signals so they can spend more time directing program
%%flow instead. Go fits in well with such a system because its goroutines can be
%%used to concurrently monitor state and channels can be used to relay that information
%%back to a central coordinator. When an output must be switched, G.E.R.T simply
%%issues a driver call that changes the behavior of a peripheral.


%Stay tuned!
%Modern embedded systems are composed of multicore SOCs that require
%careful thought about race conditions and event serialization. Like
%operating system kernels, most of these embedded systems are still implemented
%in C because it is a simplistic language that makes it good for "bare-metal"
%development.
%
%
%outline:
%computers are quicker and multicore programming is scary, but everyone still uses C
%
%C's simplicity makes it error prone for concurrent programs.
%Because C is very simple, the programmer must implement additional complexities in order to write
%concurrent programs.
%
%try2:
%Low-level system code has been written in C since the 1970's because it is powerful
%and reliable. C can be used to express any operation a computer can do and it can also be
%compiled to fast byte code. Once, during an interview, an engineer even remarked: "If you
%can't do it in C, you can't do it". This does not mean that C is always the best choice though.
%
%Even though multicore systems are commonplace now, kernels are still written in C.
%
%Writing complex concurrent programs in C is too hard. Because C is very simple,
%the programmer must implement additional complexities in order to write
%concurrent programs.
%
%
%There are very
%few built-in abstractions so it is left to the programmer to layer additional complexities
%in order to accomplish a task.
%
%
%try 1:
%Low-level system code has been written in C since the 1970's because C is powerful
%and reliable. C can be used to express any operation a computer can do and it doesn't come
%with any baggage like languages with a runtime do. C is also easy to learn because it doesn't
%require advanced degrees in order to comprehend, like Haskell and Coq do. The problems with C
%only begin to show when concurrency comes into play. C, by itself, has no idea of concurrency
%or concurrent programming patterns. It is really all up to the programmer to lay down these
%abstractions. Combined with the burden of manual memory management, concurrent programming in C
%almost always results in pouring over JTAG trace logs for hints of a race condition.
%  Faced with this bleak outlook, perhaps it is reasonable to take a performance hit in exchange for
%faster development and less bugs. After all, computers have gotten significantly quicker in
%the last 20 years. This is where Go can come in. Go is meant to be a systems language
%that provides fundamental support for concurrency and cummincation
